package cn.rxmind.dlog.db.starter.configuration;

import cn.rxmind.dlog.common.*;
import cn.rxmind.dlog.common.buffer.BlockQueueBuffer;
import cn.rxmind.dlog.common.constant.DLogConstant;
import cn.rxmind.dlog.common.rule.AnnotationNeedCopy;
import cn.rxmind.dlog.common.interceptor.UriRuleDLogInterceptor;
import cn.rxmind.dlog.common.sender.db.DBDLogDataSender;
import cn.rxmind.dlog.common.sender.db.DLogSqlProvider;
import cn.rxmind.dlog.db.starter.properties.DBProperties;
import cn.rxmind.dlog.db.starter.properties.DataSourceProperties;
import cn.rxmind.dlog.db.starter.properties.MainDLogProperties;
import com.alibaba.druid.pool.DruidDataSource;
import com.google.gson.Gson;
import org.aspectj.lang.JoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.sql.DataSource;
import java.util.Set;
import java.util.function.Predicate;

/**
 *
 * @description starter的核心配置类
 *
 * @author renxin
 * @email renxinzhiliangzhi@163.com
 * @date 2020/7/13 3:39 下午
 */
@Configuration
@EnableConfigurationProperties({DataSourceProperties.class, DBProperties.class ,MainDLogProperties.class})
public class DLogAutoConfiguration implements WebMvcConfigurer {

    private static final Gson GSON = new Gson();

    @Autowired
    private DataSourceProperties dataSourceProperties;

    @Autowired
    private DBProperties dbConfiguration;

    @Autowired
    private MainDLogProperties mainDLogProperties;

    @Autowired
    private ApplicationContext applicationContext;


    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(applicationContext.getBean(AbstractDLogInterceptor.class));
    }

    /**
     * 数据发送监听器，发送方法的实现上，可以采用线程池异步发送，根据现实需要再来决定是否应该增加线程池配置
     *
     * @param dLogDataBuffer
     * @param dLogDataSender
     * @return
     */
    @Bean
    public DLogDataCanSendListener dLogDataCanSendListener(DLogDataBuffer dLogDataBuffer,DLogDataSender dLogDataSender){

        return new DLogDataCanSendListener(dLogDataBuffer,dLogDataSender);
    }

    /**
     * 数据发送器
     *
     * @return
     */
    @Bean
    public DLogDataSender dLogDataSender(){

        Gson GSON = new Gson();
        return new DBDLogDataSender(dataSource(), new DLogSqlProvider() {
            @Override
            public String getTableName() {
                return dbConfiguration.getTableName();
            }

            @Override
            public Set<String> getColumnNames() {
                return dbConfiguration.getColumnMapping().keySet();
            }

            @Override
            protected Object mappingValue(String column, DLogData dLogData) {

                return  GSON.toJson(dLogData.getValue(dbConfiguration.getColumnMapping().get(column)));
            }
        });

    }

    /**
     * 创建拦截器
     *
     * @param dLogDataBuffer
     * @return
     */
    @Bean
    public AbstractDLogInterceptor abstractDLogInterceptor(DLogDataBuffer dLogDataBuffer){

        return new UriRuleDLogInterceptor(mainDLogProperties,dLogDataBuffer,applicationContext);
    }

    /**
     * 创建数据缓冲区
     *
     * @return
     */
    @Bean
    public DLogDataBuffer dLogDataBuffer(){
        return new BlockQueueBuffer(mainDLogProperties.getSendBatchCount()*2);
    }

    /**
     * 注入接口拦截切面
     *
     * @param needCopyData
     * @return
     */
    @Bean
    public DLogAspect dLogAspect(Predicate<JoinPoint> needCopyData){

        return new DLogAspect(needCopyData);
    }

    /**
     * 注入数据接口数据拷贝判断器
     *
     * @return
     */
    @Bean
    public Predicate<JoinPoint> needCopyData(){

       return new AnnotationNeedCopy();
    }

    /**
     * 注入Druid数据源
     *
     * @return
     */
    @Bean(DLogConstant.DATA_SOURCE_NAME)
    public DataSource dataSource(){

        DruidDataSource dataSource = new DruidDataSource();

        dataSource.setName("DLog_DataSource" + "-" + System.currentTimeMillis());
        dataSource.setUsername(dataSourceProperties.getUsername());
        dataSource.setPassword(dataSourceProperties.getPassword());
        dataSource.setUrl(dataSourceProperties.getUrl());
        dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());

        dataSource.setInitialSize(dataSourceProperties.getInitialSize());
        dataSource.setMaxActive(dataSourceProperties.getMaxActive());
        dataSource.setMaxWait(dataSourceProperties.getMaxWait());
        dataSource.setPoolPreparedStatements(dataSourceProperties.isPoolPreparedStatements());
        dataSource.setMaxOpenPreparedStatements(dataSourceProperties.getMaxOpenPreparedStatements());
        dataSource.setValidationQuery(dataSourceProperties.getValidationQuery());
        dataSource.setTestOnBorrow(dataSourceProperties.isTestOnBorrow());
        dataSource.setTestOnReturn(dataSourceProperties.isTestOnReturn());

        return dataSource;
    }

}
